package unotify

import (
	"fmt"
	"sync"
	"container/list"
	"time"
	"strings"
	"github.com/astaxie/beego/logs"
)

const (
	InfoGrade = "通知"
	WarnGrade = "告警"
	ErrorGrade = "错误"

	DefaultTitle = "CouldWorm"
)

type IMNotifyItem struct {
	Grade                   string
	Title                   string
	Msg                     string
	IMUsers                 []string
	TargetType              int
}

// SendAync IM Notify 异步发送
// 业务逻辑中执行发送之后，等到一定条件才发出
func (i *IMNotify) SendAsync(item *IMNotifyItem) error {

	// 判断防止，内存爆满
	if i.List.Len() > i.ListSize {
		return fmt.Errorf("im notify list size over load")
	}
	// list尾部加入一条记录
	i.List.PushBack(item)

	// 当长度超过设置MaxSendSize的3倍时，通知一次
	if i.List.Len() >= i.MaxSendSize * 3 {
		select {
		case i.Notify <- 1:
		default:
		}
	}

	return nil
}

// SendSync IM Notify 同步发送
// 立即发送到 server，即时发出
func (i *IMNotify) SendSync(item *IMNotifyItem) error {

	msg := fmt.Sprintf("[%s][%s]%s", item.Grade, item.Title, item.Msg)
	return i.Channel.Send(msg, item.TargetType, item.IMUsers)
}

// run msg的常驻协程
// 只要Notify的通知来得够快（会保证不超过10qps），则超时的永远不发生。
func (i *IMNotify) run()  {

	for {
		select {
		case <- i.Notify:
			// 收到通知，可以发送
			i.merge()
			time.Sleep(10 * time.Second)              // 控制速度不超过10qps
		case <- time.After(i.DurationTime):
			// 发生超时，然后尝试发送
			i.merge()
		}
	}

	return
}

// merge im消息合并，然后发送
func (i *IMNotify) merge() {

	userMsg := make(map[string]string)
	userMsg["all"] = ""

	for n := 0; n < i.MaxSendSize; n++ {
		one := i.List.Front()
		if one == nil {
			break
		}
		item := i.List.Remove(one).(*IMNotifyItem)

		if item.TargetType == TargetTypeAll {
			l := fmt.Sprintf("[%s][%s]%s", item.Grade, item.Title, item.Msg)
			userMsg["all"] = fmt.Sprintf("%s;\n%s", userMsg["all"], l)
			continue
		}

		for _, u := range item.IMUsers {
			msg, exist := userMsg[u]
			if exist == false {
				userMsg[u] = fmt.Sprintf("[%s][%s]%s", item.Grade, item.Title, item.Msg)
			} else {
				l := fmt.Sprintf("[%s][%s]%s", item.Grade, item.Title, item.Msg)
				userMsg[u] = fmt.Sprintf("%s;\n%s", msg, l)
			}
		}
	}

	for k, _ := range userMsg {
		userMsg[k] = strings.Trim(userMsg[k], ";\n")
		if len(userMsg[k]) <= 0 {
			continue
		}
		if k == "all" {
			err := i.Channel.Send(userMsg[k], TargetTypeAll, []string{k})
			if err != nil {
				logs.Error(err)
			}
		} else {
			err := i.Channel.Send(userMsg[k], TargetTypeUser, []string{k})
			if err != nil {
				logs.Error(err)
			}
		}
	}
}

func (i *IMNotify) bootStrap()  {
	i.Channel.SetConfig()

	// 队列相关的初始化处理
	i.DurationTime = i.Channel.GetDuration()
	i.MaxSendSize = i.Channel.GetMaxSendSize()

	i.ListSize = 10240
	i.Notify = make(chan int, 1)                  // 使用100的容量，是避免发生阻塞处理

	go i.run()
	return
}

// IMNotifyInstance 推送的实例对象
type IMNotify struct {
	sync.RWMutex                    // 加入一个读写锁，避免重复初始化处理
	init            bool

	Channel 		IMChannel
	IMMsgCache                      // IM消息缓存
}

type IMMsgCache struct {
	DurationTime	time.Duration
	MaxSendSize		int

	List            list.List
	ListSize        int             // list的容量值
	Notify          chan int
}

func (i *IMNotify) SetChannel(channel IMChannel)  {
	if IMNotifyInst.init == true {
		return
	}
	// 初始化
	i.Lock()
	i.Channel = channel
	i.bootStrap()
	i.init = true
	i.Unlock()

	return
}

var IMNotifyInst *IMNotify
var imNotifyOnce   sync.Once

// init 初始化接口
func init() {
	imNotifyOnce.Do(func() {
		IMNotifyInst = new(IMNotify)
		IMNotifyInst.init = false
	})
}
